package com.turingoal.license.generator;

import com.turingoal.license.TgLicense;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.security.KeyPair;
import java.security.interfaces.RSAPrivateKey;
import java.util.Base64;

/**
 * 序列号生成工具
 */
public final class TgLicenseGenerator {
    private static final byte[] HEADER = {'t', 'U', 'r', 'l', 'n', 'G', '0', 'A', 'l'}; // 头部
    private static final Logger logger = LoggerFactory.getLogger(TgLicenseGenerator.class); // 日志

    private TgLicenseGenerator() {
        throw new Error("工具类不能实例化！");
    }

    /**
     * 创建license并写到文件, 秘钥加密，公钥放到license文件里
     * 1、签名等 2、序列化 3、加密 4、前面加入公钥 5、转bas464 6、加入头
     */
    public static byte[] createLicenseAndSerialized(final TgLicense tgLicenseInfo, final KeyPair keyPair) {
        warpLicense(tgLicenseInfo); // 加入签名等
        byte[] objBytes = serialize(tgLicenseInfo); // 序列化
        byte[] encryptedBytes = TgLicenseEncryptUtil.encryptByPrivateKey(objBytes, ((RSAPrivateKey) keyPair.getPrivate()).getEncoded()); // 加密
        encryptedBytes = concateByteArray(keyPair.getPublic().getEncoded(), encryptedBytes); // 前面加入294为的公钥
        byte[] base64Bytes = Base64.getEncoder().encode(encryptedBytes); // 转base64
        base64Bytes = concateByteArray(HEADER, base64Bytes); // 加入头
        return base64Bytes;
    }

    /**
     * 创建license并写到文件
     */
    public static void createLicenseAndSaveFile(final TgLicense tgLicenseInfo, final KeyPair keyPair, final String destFilePath) {
        writeBytes(createLicenseAndSerialized(tgLicenseInfo, keyPair), destFilePath);
    }

    /**
     * warpLicense
     */
    private static final void warpLicense(final TgLicense tgLicenseInfo) {
        if (TgConstantLicenseTypes.LICENSE_TYPE_DEV.equals(tgLicenseInfo.getLicenseType())) {  // 开发版
            logger.debug("*************** 开发版  ***************");
        } else if (TgConstantLicenseTypes.LICENSE_TYPE_FREE.equals(tgLicenseInfo.getLicenseType())) {   // 免费版
            logger.debug("*************** 免费版 ***************");
        } else {
            logger.debug("*************** 专业版 ***************");
        }
        String licenseSign = TgLicenseSignUtil.sign(tgLicenseInfo); // 签名
        tgLicenseInfo.setLicenseSign(licenseSign); // 签名，防篡改
    }

    /**
     * 拼接数组
     */
    private static byte[] concateByteArray(byte[] array1, byte[] array2) {
        if (array1 == null || array1.length == 0) {
            return array2;
        } else if (array2 == null || array2.length == 0) {
            return array1;
        } else {
            byte[] result = new byte[array1.length + array2.length];
            System.arraycopy(array1, 0, result, 0, array1.length);
            System.arraycopy(array2, 0, result, array1.length, array2.length);
            return result;
        }
    }

    /**
     * 序列化<br>
     * 对象必须实现Serializable接口
     *
     * @param obj 要被序列化的对象
     * @return 序列化后的字节码
     */
    private static byte[] serialize(TgLicense obj) {
        byte[] bytes = null;
        if (obj != null) {
            try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos)) {
                oos.writeObject(obj);
                oos.flush();
                bytes = bos.toByteArray();
            } catch (IOException ex) {
                logger.error("序列化失败：" + ex.getMessage());
            }
        }
        return bytes;
    }


    /**
     * 写数据到文件中<br>
     *
     * @param bytes        数据
     * @param absolutePath 绝对路径
     * @return 目标文件
     */
    private static File writeBytes(final byte[] bytes, final String absolutePath) {
        File file = null;
        if (bytes != null) {
            if (absolutePath != null && !absolutePath.isBlank()) {
                file = new File(absolutePath);
                try (FileOutputStream fos = new FileOutputStream(file); BufferedOutputStream bos = new BufferedOutputStream(fos)) {
                    bos.write(bytes);
                } catch (IOException e) {
                    logger.debug("生成文件失败：" + e.getMessage());
                    throw new RuntimeException(e);
                }
            } else {
                logger.debug("absolutePath路径为空");
            }
        } else {
            logger.debug("文件内容为空");
        }
        return file;
    }
}
